﻿using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.ILAst;
using Mono.Cecil;

namespace CSLua
{
	// Token: 0x0200001D RID: 29
	public abstract class ExpressionBuilder : BuildFilePhase
	{
		// Token: 0x1700002F RID: 47
		// (get) Token: 0x06000100 RID: 256
		protected abstract Dictionary<string, string> operateMapping_1 { get; }

		// Token: 0x17000030 RID: 48
		// (get) Token: 0x06000101 RID: 257
		protected abstract Dictionary<string, string> operateMapping_2 { get; }

		// Token: 0x06000102 RID: 258 RVA: 0x00005C77 File Offset: 0x00003E77
		public ExpressionBuilder(MethodBodyPhase methodBuilder, ILExpression expressionContext) : base(methodBuilder)
		{
			this.methodBuilder = methodBuilder;
			this.method = methodBuilder.Method;
			this.expressionContext = expressionContext;
		}

		// Token: 0x06000103 RID: 259 RVA: 0x00005C9C File Offset: 0x00003E9C
		public static void Build(MethodBodyPhase method, ILExpression expression)
		{
			try
			{
				method.CreateExpressionBuilder(expression).BuildImpl(expression);
			}
			catch (Exception ex)
			{
				Console.Error.WriteLine("Expression Build Exception:" + ex.Message);
				Console.Error.WriteLine("Stack:" + ex.StackTrace);
				method.writer.reportExpressionError(method, expression, expression, ex.ToString());
			}
		}

		// Token: 0x06000104 RID: 260 RVA: 0x00005D14 File Offset: 0x00003F14
		public static void buildExpItem(MethodBodyPhase method, ILExpression expression)
		{
			method.CreateExpressionBuilder(expression).buildExpItemImpl(expression);
		}

		// Token: 0x06000105 RID: 261 RVA: 0x00005D23 File Offset: 0x00003F23
		public void BuildImpl(ILExpression expression)
		{
			if (BuildConfig.commentILExpression)
			{
				this.writer.commentLine(expression.ToString());
			}
			this.buildExpItemImpl(expression);
			this.writer.nextLine();
		}

		// Token: 0x06000106 RID: 262 RVA: 0x00005D54 File Offset: 0x00003F54
		private bool checkSkipExpression(ILExpression expression)
		{
			if (expression.Code == ILCode.Stloc)
			{
				ILVariable checkVer = expression.Operand as ILVariable;
				if (checkVer != null && checkVer.OriginalVariable != null && this.buildContext.isLambdaType(checkVer.OriginalVariable.VariableType))
				{
					return true;
				}
			}
			if (expression.Code == ILCode.Stfld)
			{
				ILVariable checkVer2 = expression.Arguments[0].Operand as ILVariable;
				if (checkVer2 != null && checkVer2.OriginalVariable != null && this.buildContext.isLambdaType(checkVer2.OriginalVariable.VariableType))
				{
					return true;
				}
			}
			return false;
		}

		// Token: 0x06000107 RID: 263 RVA: 0x00005DE8 File Offset: 0x00003FE8
		private void assertArg(ILExpression exp, int arg)
		{
			BuildFilePhase.Assert(exp.Arguments.Count == arg, string.Concat(new object[]
			{
				"assert args count fail except:",
				arg,
				" now:",
				exp.Arguments.Count
			}));
		}

		// Token: 0x06000108 RID: 264 RVA: 0x00005E3F File Offset: 0x0000403F
		private string getExpressionOperandLocal(ILExpression expression)
		{
			return this.methodBuilder.getNamedLocalValue(expression);
		}

		// Token: 0x06000109 RID: 265 RVA: 0x00005E4D File Offset: 0x0000404D
		private int getExpressionOperandLocalIndex(ILExpression expression)
		{
			return this.methodBuilder.getNamedLocalValueIndex(expression);
		}

		// Token: 0x0600010A RID: 266 RVA: 0x00005E5C File Offset: 0x0000405C
		private bool isConvertIntToBoolExpression(ILExpression expression)
		{
			TypeReference InferredType = expression.InferredType;
			TypeReference ExpectedType = expression.ExpectedType;
			return InferredType != null && ExpectedType != null && (InferredType.isIntType() || ExpressionBuilder.isEnumType(InferredType)) && ExpectedType.isTypeOf<bool>();
		}

		// Token: 0x0600010B RID: 267 RVA: 0x00005E98 File Offset: 0x00004098
		private bool isConvertNativeEnumToBoolExpression(ILExpression expression)
		{
			TypeReference InferredType = expression.InferredType;
			TypeReference ExpectedType = expression.ExpectedType;
			return InferredType != null && ExpectedType != null && (this.buildContext.isNativeCSType(InferredType) && ExpressionBuilder.isEnumType(InferredType)) && ExpectedType.isTypeOf<bool>();
		}

		// Token: 0x0600010C RID: 268 RVA: 0x00005EDC File Offset: 0x000040DC
		private static bool isEnumType(TypeReference t)
		{
			TypeDefinition type = t.Resolve();
			return type != null && type.IsEnum;
		}

		// Token: 0x0600010D RID: 269 RVA: 0x00005EFC File Offset: 0x000040FC
		private bool isConvertBoolToIntExpression(ILExpression expression)
		{
			TypeReference InferredType = expression.InferredType;
			TypeReference ExpectedType = expression.ExpectedType;
			return InferredType != null && ExpectedType != null && InferredType.isTypeOf<bool>() && ExpectedType.isIntType();
		}

		// Token: 0x0600010E RID: 270 RVA: 0x00005F30 File Offset: 0x00004130
		private MemberReference GetCallMemberReference(ILExpression expression)
		{
			ILCode Code = expression.Code;
			if (Code == ILCode.Call || Code == ILCode.Callvirt || Code == ILCode.CallGetter || Code == ILCode.CallvirtGetter || Code == ILCode.CallSetter || Code == ILCode.CallvirtSetter)
			{
				return (MemberReference)expression.Operand;
			}
			return null;
		}

		// Token: 0x0600010F RID: 271 RVA: 0x00005F7C File Offset: 0x0000417C
		private bool checkNeedValueCopy(ILExpression expression)
		{
			ILCode Code = expression.Code;
			if (Code == ILCode.DefaultValue || Code == ILCode.Newobj)
			{
				return false;
			}
			MemberReference callRef = this.GetCallMemberReference(expression);
			if (callRef != null && (this.buildContext.isNativeCSType(callRef.DeclaringType) || this.buildContext.IsNewValueFunc(callRef)))
			{
				return false;
			}
			ILNode parentNode = this.methodBuilder.getParentNode(expression);
			if (parentNode is ILExpression)
			{
				ILExpression parentExpression = (ILExpression)parentNode;
				ILCode parendCode = parentExpression.Code;
				if (parendCode == ILCode.Ldfld || parendCode == ILCode.Ldflda || parendCode == ILCode.Ldftn)
				{
					return false;
				}
				MemberReference callerRef = this.GetCallMemberReference(parentExpression);
				if (callerRef != null && (this.buildContext.isNativeCSType(callerRef.DeclaringType) || this.buildContext.IsImmutableValueFunc(callerRef)))
				{
					return false;
				}
			}
			return expression.ExpectedType != null && expression.InferredType != null && (this.isCopyValueType(expression.ExpectedType) || this.isCopyValueType(expression.InferredType));
		}

		// Token: 0x06000110 RID: 272 RVA: 0x0000606B File Offset: 0x0000426B
		private bool isCopyValueType(TypeReference type)
		{
			return !this.buildContext.isRebind(type) && (type.IsValueType && !type.Resolve().IsEnum && !type.isBasicType()) && !type.isTypeOf<IntPtr>();
		}

		// Token: 0x06000111 RID: 273 RVA: 0x000060A8 File Offset: 0x000042A8
		protected void buildExpItemImpl(ILExpression expression)
		{
			object operand = expression.Operand;
			bool intToBool = this.isConvertIntToBoolExpression(expression);
			this.isConvertBoolToIntExpression(expression);
			bool nativeEnumToBool = this.isConvertNativeEnumToBoolExpression(expression);
			bool needValueCopy = this.checkNeedValueCopy(expression);
			if (needValueCopy)
			{
				this.writer.code(this.buildContext.getCSLLibs(CSLLibs.CSLValueCopy)).code("(");
			}
			if (intToBool || nativeEnumToBool)
			{
				this.writer.code("(");
			}
			List<ILExpression> args = expression.Arguments;
			ILExpression arg2 = (args.Count >= 2) ? args[1] : null;
			if (args.Count >= 3)
			{
				ILExpression ilexpression = args[2];
			}
			ILCode code = expression.Code;
			if (code != ILCode.Ldnull)
			{
				switch (code)
				{
				case ILCode.Ldc_I4:
				case ILCode.Ldc_I8:
					this.assertArg(expression, 0);
					if (expression.ExpectedType == null)
					{
						this.writer.code(expression.Operand.ToString());
						goto IL_1225;
					}
					if (expression.ExpectedType.isTypeOf<bool>())
					{
						this.writer.luaBoolean((int)expression.Operand != 0);
						goto IL_1225;
					}
					if (expression.ExpectedType.Resolve().IsEnum && !this.buildContext.isLuaType(expression.ExpectedType))
					{
						this.writeEnumValue(expression.ExpectedType, (int)expression.Operand);
						goto IL_1225;
					}
					if (expression.ExpectedType.isTypeOf<ulong>() || expression.ExpectedType.isTypeOf<uint>())
					{
						uint ival = (uint)((int)expression.Operand);
						this.writer.code(ival.ToString());
						goto IL_1225;
					}
					this.writer.code(expression.Operand.ToString());
					goto IL_1225;
				case ILCode.Ldc_R4:
					this.assertArg(expression, 0);
					this.writer.luaNumber((float)expression.Operand);
					goto IL_1225;
				case ILCode.Ldc_R8:
					this.assertArg(expression, 0);
					this.writer.luaNumber((double)expression.Operand);
					goto IL_1225;
				case ILCode.Dup:
				case ILCode.Pop:
				case ILCode.Jmp:
				case ILCode.Calli:
					break;
				case ILCode.Call:
					if (!this.tryBuildOperate(expression))
					{
						this.buildCallExp(false, expression);
						goto IL_1225;
					}
					goto IL_1225;
				case ILCode.Ret:
					this.writer.code("return ");
					if (expression.Arguments.Count > 0)
					{
						this.assertArg(expression, 1);
						this.buildExpItemImpl(expression.Arguments[0]);
						goto IL_1225;
					}
					goto IL_1225;
				default:
				{
					switch (code)
					{
					case ILCode.Add:
						this.buildOptExp2(expression, "+", true);
						goto IL_1225;
					case ILCode.Sub:
						this.buildOptExp2(expression, "-", true);
						goto IL_1225;
					case ILCode.Mul:
						this.buildOptExp2(expression, "*", true);
						goto IL_1225;
					case ILCode.Div:
						if (expression.ExpectedType.isIntType() || expression.InferredType.isIntType())
						{
							this.writer.code("math.floor(");
							this.buildOptExp2(expression, "/", false);
							this.writer.code(")");
							goto IL_1225;
						}
						if (expression.ExpectedType.isFloatType())
						{
							this.buildOptExp2(expression, "/", false);
							goto IL_1225;
						}
						this.writer.reportExpressionNotsupport(this.methodBuilder, expression, this.expressionContext);
						goto IL_1225;
					case ILCode.Div_Un:
					case ILCode.Rem_Un:
					case ILCode.Xor:
					case ILCode.Shl:
					case ILCode.Shr:
					case ILCode.Shr_Un:
					case ILCode.Not:
					case ILCode.Cpobj:
					case ILCode.Ldobj:
					case ILCode.Stobj:
					case ILCode.Conv_Ovf_I1_Un:
					case ILCode.Conv_Ovf_I2_Un:
					case ILCode.Conv_Ovf_I4_Un:
					case ILCode.Conv_Ovf_I8_Un:
					case ILCode.Conv_Ovf_U1_Un:
					case ILCode.Conv_Ovf_U2_Un:
					case ILCode.Conv_Ovf_U4_Un:
					case ILCode.Conv_Ovf_U8_Un:
					case ILCode.Conv_Ovf_I_Un:
					case ILCode.Conv_Ovf_U_Un:
					case ILCode.Conv_Ovf_I1:
					case ILCode.Conv_Ovf_U1:
					case ILCode.Conv_Ovf_I2:
					case ILCode.Conv_Ovf_U2:
					case ILCode.Conv_Ovf_I4:
					case ILCode.Conv_Ovf_U4:
					case ILCode.Conv_Ovf_I8:
					case ILCode.Conv_Ovf_U8:
					case ILCode.Refanyval:
					case ILCode.Ckfinite:
					case ILCode.Mkrefany:
					case ILCode.Conv_U2:
					case ILCode.Conv_U1:
					case ILCode.Conv_Ovf_I:
					case ILCode.Conv_Ovf_U:
					case ILCode.Add_Ovf:
					case ILCode.Add_Ovf_Un:
					case ILCode.Mul_Ovf:
					case ILCode.Mul_Ovf_Un:
					case ILCode.Sub_Ovf:
					case ILCode.Sub_Ovf_Un:
					case ILCode.Endfinally:
					case ILCode.Leave:
					case ILCode.__Leave_S:
					case ILCode.__Stind_I:
					case ILCode.Conv_U:
					case ILCode.Arglist:
					case ILCode.__Ldarg:
					case ILCode.__Ldarga:
					case ILCode.__Starg:
					case ILCode.Localloc:
					case ILCode.Endfilter:
					case ILCode.Unaligned:
					case ILCode.Volatile:
					case ILCode.Tail:
					case ILCode.Initobj:
					case ILCode.Constrained:
					case ILCode.Cpblk:
					case ILCode.Initblk:
					case ILCode.No:
					case ILCode.Rethrow:
					case ILCode.Sizeof:
					case ILCode.Refanytype:
					case ILCode.Readonly:
					case ILCode.Ldexception:
					case ILCode.NullCoalescing:
					case ILCode.Wrap:
					case ILCode.InitializedObject:
					case ILCode.TernaryOp:
					case ILCode.LoopContinue:
					case ILCode.Ldc_Decimal:
					case ILCode.CompoundAssignment:
					case ILCode.PostIncrement:
					case ILCode.PostIncrement_Ovf:
					case ILCode.PostIncrement_Ovf_Un:
						goto IL_120D;
					case ILCode.Rem:
						this.buildOptExp2(expression, "%", true);
						goto IL_1225;
					case ILCode.And:
						if (expression.InferredType.isTypeOf<bool>())
						{
							this.buildOptExp2(expression, this.writer.tokens.AND, true);
							goto IL_1225;
						}
						this.writer.reportExpressionNotsupport(this.methodBuilder, this.expressionContext, expression);
						goto IL_1225;
					case ILCode.Or:
					case ILCode.LogicOr:
						this.buildOptExp2(expression, this.writer.tokens.OR, true);
						goto IL_1225;
					case ILCode.Neg:
						this.buildOptExp1(expression, "-", true);
						goto IL_1225;
					case ILCode.Conv_I1:
					case ILCode.Conv_I2:
					case ILCode.Conv_I4:
					case ILCode.Conv_I8:
					case ILCode.Conv_U4:
					case ILCode.Conv_U8:
					case ILCode.Conv_I:
						this.assertArg(expression, 1);
						this.writeCallFunc("math.floor", expression.Arguments);
						goto IL_1225;
					case ILCode.Conv_R4:
					case ILCode.Conv_R8:
					case ILCode.Conv_R_Un:
					case ILCode.Unbox:
					case ILCode.Box:
					case ILCode.Unbox_Any:
					case ILCode.AddressOf:
						this.assertArg(expression, 1);
						this.buildExpItemImpl(expression.Arguments.First<ILExpression>());
						goto IL_1225;
					case ILCode.Callvirt:
						this.buildCallExp(true, expression);
						goto IL_1225;
					case ILCode.Ldstr:
						this.assertArg(expression, 0);
						this.writer.stringLite(expression.Operand.ToString());
						goto IL_1225;
					case ILCode.Newobj:
						this.buildNewOperator(expression);
						goto IL_1225;
					case ILCode.Castclass:
					{
						this.assertArg(expression, 1);
						if (!(operand is TypeReference))
						{
							throw new Exception();
						}
						TypeReference type = (TypeReference)operand;
						if (type.Resolve().hasAttributes(BuildConfig.protoAttribute) || type.Resolve().IsInterface)
						{
							this.buildExpItemImpl(expression.Arguments.First<ILExpression>());
							goto IL_1225;
						}
						if (type.isSubTypeOf<Delegate>())
						{
							this.buildExpItemImpl(expression.Arguments.First<ILExpression>());
							goto IL_1225;
						}
						string typeId = this.buildContext.getTypeId(type, false);
						string funcName = this.buildContext.getCSLLibs("CSLStaticCast");
						this.writer.codeFormat(" {0}({1},", new object[]
						{
							funcName,
							typeId
						});
						this.buildExpItemImpl(expression.Arguments.First<ILExpression>());
						this.writer.code(")");
						goto IL_1225;
					}
					case ILCode.Isinst:
					{
						this.assertArg(expression, 1);
						string typeId2 = null;
						if (operand is GenericParameter)
						{
							typeId2 = ((GenericParameter)operand).luaIdentifier();
						}
						else if (operand is TypeReference)
						{
							typeId2 = this.buildContext.getTypeId((TypeReference)operand, false);
						}
						string funcName2 = this.buildContext.getCSLLibs("CSLDynamicCast");
						if (expression.ExpectedType != null && expression.ExpectedType.isTypeOf<bool>())
						{
							funcName2 = this.buildContext.getCSLLibs("CSLInstanceof");
						}
						this.writer.codeFormat(" {0}({1},", new object[]
						{
							funcName2,
							typeId2
						});
						this.buildExpItemImpl(expression.Arguments.First<ILExpression>());
						this.writer.code(")");
						goto IL_1225;
					}
					case ILCode.Throw:
						this.assertArg(expression, 1);
						this.writer.code(this.buildContext.getCSLLibs("CSLThrow") + "(");
						this.buildExpItemImpl(expression.Arguments[0]);
						this.writer.code(")");
						goto IL_1225;
					case ILCode.Ldfld:
					case ILCode.Ldflda:
						this.buildPropertyExp(expression, false);
						goto IL_1225;
					case ILCode.Stfld:
						this.buildPropertyExp(expression, true);
						goto IL_1225;
					case ILCode.Ldsfld:
					case ILCode.Ldsflda:
					{
						this.assertArg(expression, 0);
						FieldReference field = (FieldReference)expression.Operand;
						this.writer.code(this.buildContext.getStaticFieldId(field));
						goto IL_1225;
					}
					case ILCode.Stsfld:
					{
						this.assertArg(expression, 1);
						FieldReference field2 = (FieldReference)expression.Operand;
						if (expression.ExpectedType == null)
						{
							this.writer.code(this.buildContext.getStaticFieldId(field2) + " = ");
							this.buildExpItemImpl(expression.Arguments[0]);
							goto IL_1225;
						}
						this.writer.code(this.buildContext.getCSLLibs(CSLLibs.CSLSetField) + "(").code(this.buildContext.getTypeId(field2.DeclaringType, false)).code(",").code(field2.luaIdentifier().luaLite()).code(",");
						this.buildExpItemImpl(expression.Arguments[0]);
						this.writer.code(")");
						goto IL_1225;
					}
					case ILCode.Newarr:
					{
						TypeReference arrElement = expression.InferredType.GetElementType();
						this.assertArg(expression, 1);
						string libFuncName = "CSLNewArray";
						if (arrElement.isTypeOf<byte>())
						{
							libFuncName = CSLLibs.CSLBytesNew;
						}
						this.writer.code(this.buildContext.getCSLLibs(libFuncName) + "(");
						this.buildExpItemImpl(expression.Arguments[0]);
						this.writer.code(",").code(this.buildContext.defaultValueCode(arrElement));
						this.writer.code(")");
						goto IL_1225;
					}
					case ILCode.Ldlen:
					{
						this.assertArg(expression, 1);
						ILExpression testArg = expression.Arguments.First<ILExpression>();
						if (testArg.InferredType.isTypeOf<byte[]>())
						{
							this.writer.code(this.buildContext.getCSLLibs(CSLLibs.CSLBytesLen)).code("(");
							this.buildExpItemImpl(testArg);
							this.writer.code(")");
							goto IL_1225;
						}
						this.buildExpItemImpl(testArg);
						this.writer.code(".Length");
						goto IL_1225;
					}
					case ILCode.Ldelema:
					case ILCode.Ldelem_I1:
					case ILCode.Ldelem_U1:
					case ILCode.Ldelem_I2:
					case ILCode.Ldelem_U2:
					case ILCode.Ldelem_I4:
					case ILCode.Ldelem_U4:
					case ILCode.Ldelem_I8:
					case ILCode.Ldelem_I:
					case ILCode.Ldelem_R4:
					case ILCode.Ldelem_R8:
					case ILCode.Ldelem_Ref:
					case ILCode.Ldelem_Any:
					{
						this.assertArg(expression, 2);
						string getterName = CSLLibs.CSLArrayGet;
						if (expression.Arguments.First<ILExpression>().InferredType.isTypeOf<byte[]>())
						{
							getterName = CSLLibs.CSLBytesGet;
						}
						this.writer.code(this.buildContext.getCSLLibs(getterName) + "(");
						this.buildExpItemImpl(expression.Arguments.First<ILExpression>());
						this.writer.code(",");
						this.buildExpItemImpl(expression.Arguments[1]);
						this.writer.code(")");
						goto IL_1225;
					}
					case ILCode.Stelem_I:
					case ILCode.Stelem_I1:
					case ILCode.Stelem_I2:
					case ILCode.Stelem_I4:
					case ILCode.Stelem_I8:
					case ILCode.Stelem_R4:
					case ILCode.Stelem_R8:
					case ILCode.Stelem_Ref:
					case ILCode.Stelem_Any:
					{
						this.assertArg(expression, 3);
						string getterName2 = CSLLibs.CSLArraySet;
						if (expression.Arguments.First<ILExpression>().InferredType.isTypeOf<byte[]>())
						{
							getterName2 = CSLLibs.CSLBytesSet;
						}
						this.writer.code(this.buildContext.getCSLLibs(getterName2) + "(");
						this.buildExpItemImpl(expression.Arguments.First<ILExpression>());
						this.writer.code(",");
						this.buildExpItemImpl(expression.Arguments[1]);
						this.writer.code(",");
						this.buildExpItemImpl(expression.Arguments[2]);
						this.writer.code(")");
						goto IL_1225;
					}
					case ILCode.Ldtoken:
						this.assertArg(expression, 0);
						if (expression.Operand is TypeReference)
						{
							TypeReference type2 = (TypeReference)expression.Operand;
							string typeId3 = this.buildContext.getTypeId(type2, false);
							this.writer.code(typeId3);
							goto IL_1225;
						}
						this.writer.code(" " + expression.Operand + " ");
						goto IL_1225;
					case ILCode.Ceq:
						break;
					case ILCode.Cgt:
						goto IL_BB8;
					case ILCode.Cgt_Un:
					{
						TypeReference arg1Type = expression.Arguments[0].InferredType;
						if (arg1Type != null && !arg1Type.IsValueType)
						{
							goto IL_AF9;
						}
						if (arg1Type.IsSignedIntegralType() && arg2 != null && arg2.Operand.IsZero())
						{
							goto IL_AF9;
						}
						goto IL_BB8;
					}
					case ILCode.Clt:
					case ILCode.Clt_Un:
						this.buildOptExp2(expression, "<", true);
						goto IL_1225;
					case ILCode.Ldftn:
					{
						this.assertArg(expression, 0);
						MethodReference f3 = (MethodReference)operand;
						this.writer.code(this.getUnvirtualMethodId(f3));
						goto IL_1225;
					}
					case ILCode.Ldvirtftn:
					{
						this.assertArg(expression, 0);
						MethodReference f2 = (MethodReference)operand;
						this.writer.stringLite(this.buildContext.getMethodName(f2));
						goto IL_1225;
					}
					case ILCode.Ldloc:
					case ILCode.Ldloca:
					{
						this.assertArg(expression, 0);
						bool flag = false;
						string operandStr = this.getExpressionOperandLocal(expression);
						if (flag)
						{
							this.writer.code("(0" + this.writer.tokens.NEQ + operandStr + ")");
							goto IL_1225;
						}
						this.writer.code(operandStr);
						goto IL_1225;
					}
					case ILCode.Stloc:
					{
						this.assertArg(expression, 1);
						if (expression.ExpectedType != null)
						{
							int localIndex = this.getExpressionOperandLocalIndex(expression);
							this.writer.code(string.Concat(new object[]
							{
								this.buildContext.getCSLLibs(CSLLibs.CSLSetLocal),
								"(",
								localIndex + 1,
								","
							}));
							this.buildExpItemImpl(expression.Arguments.First<ILExpression>());
							this.writer.code(")");
							goto IL_1225;
						}
						string localName = this.getExpressionOperandLocal(expression);
						this.writer.code(localName + " = ");
						this.buildExpItemImpl(expression.Arguments.First<ILExpression>());
						goto IL_1225;
					}
					case ILCode.Cne:
						goto IL_AF9;
					case ILCode.Cge:
					case ILCode.Cge_Un:
						this.buildOptExp2(expression, ">=", true);
						goto IL_1225;
					case ILCode.Cle:
						goto IL_B94;
					case ILCode.Cle_Un:
					{
						TypeReference arg1Type2 = expression.Arguments[0].InferredType;
						if ((arg1Type2 == null || arg1Type2.IsValueType) && (!arg1Type2.IsSignedIntegralType() || arg2 == null || !arg2.Operand.IsZero()))
						{
							goto IL_B94;
						}
						break;
					}
					case ILCode.LogicNot:
					{
						ILExpression notExp = expression.Arguments[0];
						if (notExp.Code == ILCode.LogicNot)
						{
							this.buildExpItemImpl(notExp.Arguments[0]);
							goto IL_1225;
						}
						this.buildOptExp1(expression, this.writer.tokens.NOT, true);
						goto IL_1225;
					}
					case ILCode.LogicAnd:
						this.buildOptExp2(expression, this.writer.tokens.AND, true);
						goto IL_1225;
					case ILCode.InitArray:
					{
						string libFuncName2 = "CSLInitArray";
						if (expression.InferredType.GetElementType().isTypeOf<byte>())
						{
							libFuncName2 = CSLLibs.CSLBytesInit;
						}
						this.writer.code(this.buildContext.getCSLLibs(libFuncName2) + "(").dot<ILExpression>(expression.Arguments, delegate(ILExpression exp, int idx)
						{
							this.buildExpItemImpl(exp);
						}).code(")");
						goto IL_1225;
					}
					case ILCode.InitObject:
						this.buildInitObject(expression);
						goto IL_1225;
					case ILCode.InitCollection:
					{
						CustomAttribute initCollectionAttribute = expression.InferredType.Resolve().getAttribute(CSLStub.InitCollectionAttribute);
						if (initCollectionAttribute != null)
						{
							this.writer.code((string)initCollectionAttribute.ConstructorArguments[0].Value + "(").dot<ILExpression>(expression.Arguments, delegate(ILExpression exp, int idx)
							{
								if (idx == 0)
								{
									this.buildExpItemImpl(exp);
									return;
								}
								if (exp.Code == ILCode.Callvirt)
								{
									this.assertArg(exp, 2);
									this.buildExpItemImpl(exp.Arguments[1]);
									return;
								}
								throw new Exception("not support operation");
							}).code(")");
							goto IL_1225;
						}
						this.writer.reportExpressionNotsupport(this.methodBuilder, this.expressionContext, expression);
						goto IL_1225;
					}
					case ILCode.LoopOrSwitchBreak:
						this.writer.code(" break ");
						goto IL_1225;
					case ILCode.YieldBreak:
						this.writer.code("if true then return end");
						goto IL_1225;
					case ILCode.YieldReturn:
					{
						this.assertArg(expression, 1);
						ILExpression ilexpression2 = expression.Arguments[0];
						this.writer.code(this.buildContext.getCSLLibs("CSLYield") + "(");
						this.buildExpItemImpl(expression.Arguments[0]);
						this.writer.code(")");
						goto IL_1225;
					}
					case ILCode.DefaultValue:
					{
						this.assertArg(expression, 0);
						TypeReference expType = expression.InferredType;
						this.writer.code(this.buildContext.defaultValueCode(expType));
						goto IL_1225;
					}
					case ILCode.CallGetter:
						this.buildPropertyAccess(expression, false, false);
						goto IL_1225;
					case ILCode.CallvirtGetter:
						this.buildPropertyAccess(expression, false, true);
						goto IL_1225;
					case ILCode.CallSetter:
						this.buildPropertyAccess(expression, true, false);
						goto IL_1225;
					case ILCode.CallvirtSetter:
						this.buildPropertyAccess(expression, true, true);
						goto IL_1225;
					default:
						goto IL_120D;
					}
					this.buildOptExp2(expression, this.writer.tokens.EQ, true);
					goto IL_1225;
					IL_AF9:
					this.buildOptExp2(expression, this.writer.tokens.NEQ, true);
					goto IL_1225;
					IL_B94:
					this.buildOptExp2(expression, "<=", true);
					goto IL_1225;
					IL_BB8:
					ILExpression right = expression.Arguments[1];
					if (right.ExpectedType.Resolve().IsEnum)
					{
						BuildFilePhase.Assert((int)right.Operand == 0, null);
						this.buildOptExp2(expression, this.writer.tokens.NEQ, true);
						goto IL_1225;
					}
					this.buildOptExp2(expression, ">", true);
					goto IL_1225;
				}
				}
				IL_120D:
				this.writer.reportExpressionNotsupport(this.methodBuilder, this.expressionContext, expression);
			}
			else
			{
				this.assertArg(expression, 0);
				this.writer.luaNil();
			}
			IL_1225:
			if (nativeEnumToBool)
			{
				TypeReference nativeEnumType = expression.InferredType;
				FieldDefinition field3 = nativeEnumType.Resolve().Fields.First((FieldDefinition f) => f.Constant is int && (int)f.Constant == 0);
				this.writer.code(this.writer.tokens.NEQ).code(this.buildContext.getTypeId(nativeEnumType, false)).code(".").code(field3.Name).code(")");
			}
			else if (intToBool)
			{
				this.writer.code(" " + this.writer.tokens.NEQ + " 0)");
			}
			if (needValueCopy)
			{
				this.writer.code(")");
			}
		}

		// Token: 0x06000112 RID: 274 RVA: 0x000073B0 File Offset: 0x000055B0
		protected void writeEnumValue(TypeReference enumType, int value)
		{
			TypeDefinition enumDef = enumType.Resolve();
			string enumId = this.buildContext.getTypeId(enumDef, false);
			FieldDefinition field = enumDef.Fields.First((FieldDefinition f) => f.Constant is int && (int)f.Constant == value);
			this.writer.code(enumId + "." + field.Name);
		}

		// Token: 0x06000113 RID: 275 RVA: 0x00007414 File Offset: 0x00005614
		protected void writeCallFunc(string func, List<ILExpression> args)
		{
			this.writer.callFunc<ILExpression>(func, args, delegate(ILExpression e, int i)
			{
				this.buildExpItemImpl(e);
			});
		}

		// Token: 0x06000114 RID: 276 RVA: 0x00007430 File Offset: 0x00005630
		protected void writeCallFunc(string func, string first, List<ILExpression> args)
		{
			this.writer.callFunc<ILExpression>(func, first, args, delegate(ILExpression e, int i)
			{
				this.buildExpItemImpl(e);
			});
		}

		// Token: 0x06000115 RID: 277 RVA: 0x00007450 File Offset: 0x00005650
		private void buildInitObject(ILExpression expression)
		{
			if (!expression.InferredType.Resolve().hasAttributes(BuildConfig.protoAttribute))
			{
				this.writer.code(this.buildContext.getCSLLibs("CSLInitObject") + "(");
				this.buildExpItemImpl(expression.Arguments.First<ILExpression>());
				this.writer.code(",");
				this.buildInitObjectRecu(expression.Arguments.GetRange(1, expression.Arguments.Count - 1), false);
				this.writer.code(")");
				return;
			}
			this.writer.code(this.buildContext.getCSLLibs("CSLRawtable") + "(");
			this.buildInitObjectRecu(expression.Arguments.GetRange(1, expression.Arguments.Count - 1), true);
			this.writer.code(")");
		}

		// Token: 0x06000116 RID: 278 RVA: 0x00007548 File Offset: 0x00005748
		private void buildInitObjectRecu(ICollection<ILExpression> expressions, bool proto)
		{
			this.writer.code("{").dot<ILExpression>(expressions, delegate(ILExpression exp, int i)
			{
				if (exp.Code == ILCode.Stfld || exp.Code == ILCode.CallSetter || exp.Code == ILCode.CallvirtSetter)
				{
					this.assertArg(exp, 2);
					MemberReference member = exp.Operand as MemberReference;
					string identifier = member.luaIdentifier();
					if ((proto || !this.buildContext.isLuaType(member.DeclaringType)) && member is MethodReference)
					{
						identifier = (member as MethodReference).toPropertyIdentifier();
					}
					this.writer.code(identifier).code("=");
					ILExpression valueExp = exp.Arguments[1];
					this.buildValueExpression(valueExp, proto);
					return;
				}
				if (exp.Code != ILCode.InitObject)
				{
					throw new Exception("Error");
				}
				this.assertArg(exp, 2);
				ILExpression getter = exp.Arguments[0];
				if (getter.Code == ILCode.Ldfld || getter.Code == ILCode.CallGetter || getter.Code == ILCode.CallvirtGetter)
				{
					MemberReference member2 = getter.Operand as MemberReference;
					string identifier2 = member2.luaIdentifier();
					if (proto && member2 is MethodReference)
					{
						identifier2 = (member2 as MethodReference).toPropertyIdentifier();
					}
					this.writer.code(identifier2).code("=");
					this.buildInitObjectRecu(exp.Arguments, proto);
					return;
				}
				throw new Exception("Error");
			}).code("}");
		}

		// Token: 0x06000117 RID: 279 RVA: 0x00007598 File Offset: 0x00005798
		private void buildNewOperator(ILExpression expression)
		{
			TypeDefinition declaringType = ((MethodReference)expression.Operand).DeclaringType.Resolve();
			if (declaringType.isDelegate())
			{
				this.buildNewDelegate(expression);
				return;
			}
			if (declaringType.hasAttributes(BuildConfig.protoAttribute))
			{
				this.assertArg(expression, 0);
				this.writer.callFunc(this.buildContext.getCSLLibs("CSLRawtable"));
				return;
			}
			this.buildNewObject(expression, declaringType, expression.Arguments);
		}

		// Token: 0x06000118 RID: 280 RVA: 0x0000760C File Offset: 0x0000580C
		private void buildNewObject(ILExpression exp, TypeDefinition type, List<ILExpression> args)
		{
			string typeName = this.buildContext.getTypeId(type, false);
			if (this.buildContext.isNativeCSType(type) && type.HasGenericParameters)
			{
				this.writer.reportExpressionError(this.methodBuilder, exp, exp, "无法构造类型:" + type);
			}
			this.writeCallFunc(this.buildContext.getCSLLibs("CSLNew"), typeName, args);
		}

		// Token: 0x06000119 RID: 281 RVA: 0x00007674 File Offset: 0x00005874
		private void buildValueExpression(ILExpression valueExp, bool isProto)
		{
			if (isProto && valueExp.ExpectedType.isSubTypeOf<Enum>())
			{
				this.writeCallFunc(this.buildContext.getCSLLibs(CSLLibs.CSLProtoEnumName), BuilderUtils.GetTypeFullname(valueExp.ExpectedType.Resolve(), true).luaLite(), new List<ILExpression>
				{
					valueExp
				});
				return;
			}
			this.buildExpItemImpl(valueExp);
		}

		// Token: 0x0600011A RID: 282 RVA: 0x000076D4 File Offset: 0x000058D4
		private void buildNewDelegate(ILExpression expression)
		{
			if (((MethodReference)expression.Arguments[1].Operand).Resolve().IsStatic)
			{
				this.buildExpItemImpl(expression.Arguments[1]);
				return;
			}
			this.writeCallFunc(this.buildContext.getCSLLibs("CSLNewfunc"), expression.Arguments);
		}

		// Token: 0x0600011B RID: 283 RVA: 0x00007734 File Offset: 0x00005934
		private void buildPropertyAccess(ILExpression expression, bool isSetter, bool isVvirtual)
		{
			MethodReference i = (MethodReference)expression.Operand;
			if (i.DeclaringType.Resolve().hasAttributes(BuildConfig.protoAttribute))
			{
				this.buildPropertyExp(expression, isSetter);
				return;
			}
			if (this.buildContext.isLuaType(i.DeclaringType) || this.buildContext.isRebind(i.DeclaringType) || (isSetter && i.Parameters.Count > 1) || (!isSetter && i.Parameters.Count >= 1))
			{
				this.buildCallExp(isVvirtual, expression);
				return;
			}
			this.buildPropertyExp(expression, isSetter);
		}

		// Token: 0x0600011C RID: 284 RVA: 0x000077C6 File Offset: 0x000059C6
		private void buildFieldAccess(ILExpression expression)
		{
			object operand = expression.Operand;
		}

		// Token: 0x0600011D RID: 285 RVA: 0x000077D0 File Offset: 0x000059D0
		private void buildPropertyExp(ILExpression expression, bool setter)
		{
			bool leftExp = true;
			MemberReference member = expression.Operand as MemberReference;
			FieldReference field = expression.Operand as FieldReference;
			bool flag = !setter;
			bool protoField = expression.InferredType.Resolve().IsEnum && member.DeclaringType.Resolve().hasAttributes(BuildConfig.protoAttribute);
			bool flag2 = flag && protoField;
			bool isProtoEnumFieldSetter = setter && protoField;
			bool isStaticMethod = member is MethodReference && ((MethodReference)member).Resolve().IsStatic;
			if (setter && expression.ExpectedType != null)
			{
				Console.Write("");
			}
			bool isAssignReturn = setter && field != null && expression.ExpectedType != null;
			if (flag2)
			{
				this.writer.code(this.buildContext.getCSLLibs(CSLLibs.CSLProtoEnumValue + "('")).code(BuilderUtils.GetTypeFullname(expression.InferredType.Resolve(), true)).code("',");
			}
			string name;
			if (field != null)
			{
				name = field.luaIdentifier();
			}
			else
			{
				MethodReference method = expression.Operand as MethodReference;
				if (!method.luaIdentifier().StartsWith("get_") && !method.luaIdentifier().StartsWith("set_"))
				{
					throw new Exception();
				}
				name = method.luaIdentifier().Substring(4);
				if (expression.Arguments.Count == 0)
				{
					this.writer.code(this.buildContext.getTypeId(method.DeclaringType, false));
					leftExp = false;
				}
			}
			if (isAssignReturn)
			{
				this.writer.code(this.buildContext.getCSLLibs(CSLLibs.CSLSetField + "("));
			}
			if (leftExp)
			{
				if (isStaticMethod)
				{
					this.writer.code(this.buildContext.getTypeId(member.DeclaringType, false));
				}
				else
				{
					this.buildExpItemImpl(expression.Arguments[0]);
				}
			}
			if (isAssignReturn)
			{
				this.writer.code("," + name.luaLite());
			}
			else
			{
				this.writer.code("." + name);
			}
			if (flag2)
			{
				this.writer.code(")");
			}
			if (setter)
			{
				if (isAssignReturn)
				{
					this.writer.code(",");
					this.buildValueExpression(expression.Arguments[(leftExp && !isStaticMethod) ? 1 : 0], protoField);
					this.writer.code(")");
					return;
				}
				this.writer.code(" = ");
				this.buildValueExpression(expression.Arguments[(leftExp && !isStaticMethod) ? 1 : 0], protoField);
			}
		}

		// Token: 0x0600011E RID: 286 RVA: 0x00007A73 File Offset: 0x00005C73
		internal string getNativeMethodFullName(MethodReference method)
		{
			return method.DeclaringType.Resolve().luaGlobalIdentifier() + "." + method.luaIdentifier();
		}

		// Token: 0x0600011F RID: 287
		protected abstract bool isForceUnvirtual(MethodReference methodRef);

		// Token: 0x06000120 RID: 288
		protected abstract bool isForceVirtualCall();

		/// <summary>
		/// 构建调用表达式
		/// </summary>
		/// <param name="isVitrual">是否为虚方法</param>
		/// <param name="expression">IL表达式</param>
		private void buildCallExp(bool isVitrual, ILExpression expression)
		{
			MethodReference methodRef = (MethodReference)expression.Operand;
			MethodDefinition methodDef = methodRef.Resolve();
			if (!methodDef.IsStatic && this.isForceVirtualCall())
			{
				isVitrual = true;
			}
			if (methodDef.isCtor() && methodDef.DeclaringType.IsValueType)
			{
				List<ILExpression> args = expression.Arguments.GetRange(1, expression.Arguments.Count - 1);
				ILExpression leftExpression = expression.Arguments[0];
				BuildFilePhase.Assert(leftExpression.Code == ILCode.Ldloca, null);
				string operandStr = this.getExpressionOperandLocal(leftExpression);
				this.writer.code(operandStr);
				this.writer.code(" = ");
				this.buildNewObject(expression, methodDef.DeclaringType, args);
				return;
			}
			if (methodDef != null && methodDef.hasAttributes(BuildConfig.ImplicitAttribute))
			{
				this.assertArg(expression, 1);
				this.buildExpItemImpl(expression.Arguments.First<ILExpression>());
				return;
			}
			if (methodDef != null && methodDef.hasAttributes(BuildConfig.ReplaceScriptAttribute))
			{
				string scriptTemplate = methodDef.getAttribute(BuildConfig.ReplaceScriptAttribute).ConstructorArguments.First<CustomAttributeArgument>().Value.ToString();
				string[] argNames = new string[expression.Arguments.Count];
				for (int i = 0; i < argNames.Length; i++)
				{
					this.writer.push();
					this.buildExpItemImpl(expression.Arguments[i]);
					string code = this.writer.popBuilder().ToString();
					argNames[i] = code;
				}
				this.writer.codeFormat(scriptTemplate, argNames);
				return;
			}
			if (methodDef != null && !methodDef.IsStatic && methodDef.Name == "ToString" && methodDef.Parameters.Count == 0)
			{
				this.writer.code("_G.tostring(");
				this.buildExpItemImpl(expression.Arguments[0]);
				this.writer.code(")");
				return;
			}
			List<string> typeArgs = new List<string>();
			if (methodRef is GenericInstanceMethod && (methodRef.Resolve().getAttribute(BuildConfig.genericParamAttribute) != null))
			{
				if (!methodDef.IsStatic)
				{
					isVitrual = true;
				}
				foreach (TypeReference gtype in (methodRef as GenericInstanceMethod).GenericArguments)
				{
					if (this.buildContext.isLuaType(methodRef.DeclaringType) || this.buildContext.isRebind(methodRef.DeclaringType))
					{
						typeArgs.Add(this.buildContext.getTypeId(gtype, false));
					}
					else
					{
						typeArgs.Add("typeof(" + this.buildContext.getTypeId(gtype, false) + ")");
					}
				}
			}
			if (isVitrual && !this.isForceUnvirtual(methodRef))
			{
				if (methodRef.DeclaringType.isDelegate())
				{
					this.writer.code(this.buildContext.getCSLLibs(CSLLibs.CSLCallDelegate + "("));
					this.buildExpItemImpl(expression.Arguments[0]);
					if (typeArgs.Count > 0 || expression.Arguments.Count > 1)
					{
						this.writer.code(",");
					}
				}
				else
				{
					this.buildExpItemImpl(expression.Arguments[0]);
					this.writer.code(this.writer.tokens.callDot + this.buildContext.getMethodName(methodRef));
					this.writer.code("(");
				}
				if (typeArgs.Count > 0)
				{
					this.writer.dot<string>(typeArgs, delegate(string targ, int idx)
					{
						this.writer.code(targ);
					});
					if (expression.Arguments.Count > 1)
					{
						this.writer.code(",");
					}
				}
				this.writer.dot<ILExpression>(expression.Arguments, delegate(ILExpression exp, int idx)
				{
					if (idx > 0)
					{
						this.buildExpItemImpl(exp);
					}
				}).code(")");
				return;
			}
			if (this.buildContext.isRebind(methodRef.DeclaringType) && !this.buildContext.checkRebindMethod(methodRef))
			{
				this.writer.code("##not implement##[=[" + expression.ToString() + "]=]");
				AssemblyGenerator.AppendError("error:##not implement##[=[" + expression.ToString() + "]=]");
				return;
			}
			if (methodRef.DeclaringType.isTypeOf<object>() && methodRef.isCtor())
			{
				return;
			}
			this.buildUnvirtualCall(this.writer, expression, methodDef, typeArgs);
		}

		// Token: 0x06000122 RID: 290
		public abstract void buildUnvirtualCall(CodeWriter writer, ILExpression expression, MethodDefinition methodDef, List<string> typeArgs);

		// Token: 0x06000123 RID: 291
		public abstract string getUnvirtualMethodId(MethodReference refe);

		// Token: 0x06000124 RID: 292 RVA: 0x00007F30 File Offset: 0x00006130
		private bool tryBuildOperate(ILExpression expression)
		{
			MethodReference methodRef = (MethodReference)expression.Operand;
			string opt;
			if (this.operateMapping_1.TryGetValue(methodRef.luaIdentifier(), out opt))
			{
				this.buildOptExp1(expression, opt, true);
				return true;
			}
			if (this.operateMapping_2.TryGetValue(methodRef.luaIdentifier(), out opt))
			{
				this.buildOptExp2(expression, opt, true);
				return true;
			}
			return false;
		}

		// Token: 0x06000125 RID: 293 RVA: 0x00007F8C File Offset: 0x0000618C
		private void buildOptExp2(ILExpression expression, string opt, bool bracket = true)
		{
			this.assertArg(expression, 2);
			if (bracket)
			{
				this.writer.code("(");
			}
			this.buildExpItemImpl(expression.Arguments[0]);
			this.writer.code(" " + opt + " ");
			this.buildExpItemImpl(expression.Arguments[1]);
			if (bracket)
			{
				this.writer.code(")");
			}
		}

		// Token: 0x06000126 RID: 294 RVA: 0x0000800C File Offset: 0x0000620C
		private void buildOptExp1(ILExpression expression, string opt, bool bracket = true)
		{
			this.assertArg(expression, 1);
			if (bracket)
			{
				this.writer.code("(");
			}
			this.writer.code(opt);
			this.buildExpItemImpl(expression.Arguments[0]);
			if (bracket)
			{
				this.writer.code(")");
			}
		}

		// Token: 0x04000069 RID: 105
		public MethodDefinition method;

		// Token: 0x0400006A RID: 106
		public MethodBodyPhase methodBuilder;

		// Token: 0x0400006B RID: 107
		public ILExpression expressionContext;
	}
}
